package com.crawler.uc.utils;

import com.crawler.common.config.JacksonObjectMapper;
import com.crawler.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;

import java.io.IOException;
import java.util.Properties;

/**
 * redis 管理器
 * @author Rubekid
 *
 * 2017年5月15日 上午10:06:24
 */
public class UcRedisManager {
	
	/**
	 * 日志
	 */
	private static Logger logger = LoggerFactory.getLogger(UcRedisManager.class);
	
	/**
	 * 
	 * jedis池
	 */
	private static JedisPool pool;
	
	private static int DB_INDEX = 0;


	 /**
	  * 静态代码初始化池配置
	  */
	static {
		try {
			
			Properties props = new Properties();
			props.load(UcRedisManager.class.getClassLoader().getResourceAsStream("uc.redis.properties"));
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxTotal(Integer.valueOf(props.getProperty("redis.pool.maxTotal")));
			config.setMaxIdle(Integer.valueOf(props.getProperty("redis.pool.maxIdle")));
			config.setMaxWaitMillis(Long.valueOf(props.getProperty("redis.pool.maxWaitMillis")));
			config.setTestOnBorrow(Boolean.valueOf(props.getProperty("redis.pool.testOnBorrow")));
			config.setTestOnReturn(Boolean.valueOf(props.getProperty("redis.pool.testOnReturn")));
			
			String host = props.getProperty("redis.host");
			Integer port = Integer.valueOf(props.getProperty("redis.port"));
			Integer timeout = Integer.valueOf(props.getProperty("redis.timeout"));
			String password = props.getProperty("redis.password");
			DB_INDEX = Integer.valueOf(props.getProperty("redis.dbindex", "0"));
			if(password !=null){
				pool = new JedisPool(config, host, port, timeout, password);
			}
			else{
				pool = new JedisPool(config, host, port, timeout);
			}

		} catch (IOException ex) {
			logger.error(ex.getMessage(), ex);
		}
	}
	
	
	/**
     * 获取Jedis实例
     * 
     * @return
     */
    public synchronized static Jedis getJedis() {
    	Jedis resource = null;
        try {
            if (pool != null) {
                resource = pool.getResource();
                resource.select(DB_INDEX);
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
        if(resource== null){        	
        	throw new NullPointerException("jedis is null, please check the redis server.");
        }
        return resource;
    }
	
    /**
     * 释放jedis资源
     * 
     * @param jedis
     */
    public static void close(final Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
    
    
    /**
     * 设置键的字符串值(指定超时)
     * @param key
     * @param data
     * @param seconds
     */
    public static void set(String key, Object data, int seconds){
    	String value = null;
    	if(data instanceof String){
    		value = String.valueOf(data);
    	}
    	else{
    		value = toJSONString(data);
    	}
    	Jedis jedis = null;
		try{
			jedis  = getJedis();
			jedis.setex(key, seconds, value);
		}
		finally{
			close(jedis);
		}
    }
    

	/**
	 * 设置值
	 * @param key
	 * @param obj
	 */
	public static void set(String key, Object data){
		String value = null;
		if(data instanceof String){
    		value = String.valueOf(data);
    	}
    	else{
    		value = toJSONString(data);
    	}
    	Jedis jedis = null;
		try{
			jedis = getJedis();
			jedis.set(key, value);
		}
		finally{
			close(jedis);
		}
	}
    
    /**
	 * 根据key 获取对象
	 * @param key
	 * @param clazz
	 * @return
	 */
	public static <T> T get(String key, Class<T> clazz){
		Jedis jedis = null;
		try{
			jedis  = getJedis();
			String value = jedis.get(key);
			if(StringUtils.isNullOrEmpty(	value)){
				return null;
			}
			return parse(value, clazz);
		}
		finally{
			close(jedis);
		}
	}
	
	/**
	 * 根据key 
	 * @param key
	 * @return
	 */
	public static String get(String key){
		Jedis jedis = null;
		try{
			jedis  = getJedis();
			return jedis.get(key);
		}
		finally{
			close(jedis);
		}
	}
	
	
	/**
	 * 删除
	 * @param key
	 */
	public static void del(String key){
		Jedis jedis = null;
		try{
			jedis = getJedis();
			jedis.del(key);
		}
		finally{
			close(jedis);
		}
	}
	
	
	/**
	 * 转字符串
	 * @param object
	 * @return
	 */
	public static String toJSONString(Object object) {
		ObjectMapper objectMapper = new JacksonObjectMapper();
		try {
			return objectMapper.writeValueAsString(object);
		} catch (JsonProcessingException ex) {
			logger.error(ex.getMessage(), ex);
		}
		return "";
	}
	
	/**
	 * 转对象
	 * @param value
	 * @param clazz
	 * @return
	 * @throws IOException
	 */
	public static <T> T parse(String value, Class<T> clazz){
		ObjectMapper objectMapper = new JacksonObjectMapper();
		try {
			return objectMapper.readValue(value, clazz);
		} catch (IOException ex) {
			logger.error(ex.getMessage(), ex);
		}
		return null;
	}
	
	/**
	 * 发布
	 * @param channel
	 * @param obj
	 */
	public static void publish(String channel, Object obj){
		Jedis jedis = null;
		try{
			jedis = getJedis();
			String data = toJSONString(obj);
			jedis.publish(channel, data);
		}
		finally{
			if(null != jedis){				
				jedis.close();
			}
		}
	}
	
	/**
	 * 订阅
	 * @param jedisPubSub
	 * @param channels
	 */
	public static void subscribe(final JedisPubSub jedisPubSub, final String... channels){
		Jedis jedis = null;
		try{
			jedis = getJedis();
			jedis.subscribe(jedisPubSub, channels);
		}
		finally{
			if(null != jedis){				
				jedis.close();
			}
		}
	}
}